home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1995 March / Macworld CD-ROM (March 1995).cdr / Updaters / Symantec C++ 6.0.1 Update / Library Updates / Standard Libraries / C sources / scanf.c < prev   
Encoding:
C/C++ Source or Header  |  1993-07-13  |  10.9 KB  |  669 lines  |  [TEXT/KAHL]

  1.  
  2. /*
  3.  *  scanf.c
  4.  *
  5.  *  Copyright (c) 1991 Symantec Corporation.  All rights reserved.
  6.  *
  7.  */
  8.  
  9. #include "stdio.h"
  10. #include "stdarg.h"
  11. #include "limits.h"
  12. #include "ctype.h"
  13. #include "errno.h"
  14. #include "ansi_private.h"
  15. #include <SANE.h>
  16.  
  17. static void clearset(int);
  18. static void invertset(void);
  19. static void setbit(int);
  20. static int testbit(int);
  21.  
  22. #define TRUE            1
  23. #define FALSE            0
  24.  
  25. static struct format {
  26.     unsigned         suppress : 1;
  27.     unsigned        haveWidth : 1;
  28.     unsigned         fetchBase : 1;
  29.     unsigned        negate : 1;
  30.     unsigned         valid : 1;
  31.     unsigned         unsigned_ : 1;
  32.     unsigned        floating : 1;
  33.     unsigned        dot : 1;
  34.     unsigned         hSize : 1;
  35.     unsigned         lSize : 1;
  36.     unsigned         LSize : 1;
  37.     int                fieldWidth;
  38. } default_format;
  39.  
  40. struct decrec {
  41.     char            sgn;
  42.     short            exp;
  43.     char            sig[SIGDIGLEN];
  44. };
  45.  
  46. static void dtof(short, struct decrec *, void *);
  47.  
  48. static char scanset[32];
  49.  
  50.  
  51. int
  52. _vfscanf(FILE *fp, const char *fmt, va_list arg)
  53. {
  54.     int nassigned = 0, nconverted = 0, nread = 0;
  55.     int overflow, state;
  56.     unsigned char first;
  57.     register short c, base, digit;
  58.     register long result;
  59.     register char *s;
  60.     struct format F;
  61.     struct decrec D;
  62.     
  63.     for (c = *fmt; c; c = *++fmt) {
  64.         if (c != '%')
  65.             goto match1;
  66.         F = default_format;
  67.         
  68.             /*  check for assignment-suppression flag  */
  69.         
  70.         c = *++fmt;
  71.         if (c == '*') {
  72.             F.suppress = TRUE;
  73.             c = *++fmt;
  74.         }
  75.         
  76.             /*  decode field width  */
  77.         
  78.         if (isdigit(c)) {
  79.             F.haveWidth = TRUE;
  80.             do {
  81.                 F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
  82.                 c = *++fmt;
  83.             } while (isdigit(c));
  84.             if (F.fieldWidth <= 0)
  85.                 goto done;
  86.         }
  87.         
  88.             /*  determine appropriate conversion  */
  89.         
  90. conv:    switch (c) {
  91.                 
  92.                 /*  'h' size modifier  */
  93.                 
  94.             case 'h':
  95.                 F.hSize = TRUE;
  96.                 c = *++fmt;
  97.                 goto conv;
  98.                 
  99.                 /*  'l' size modifier  */
  100.                 
  101.             case 'l':
  102.                 F.lSize = TRUE;
  103.                 c = *++fmt;
  104.                 goto conv;
  105.                         
  106.                 /*  'L' size modifier  */
  107.                 
  108.             case 'L':
  109.                 F.LSize = TRUE;
  110.                 c = *++fmt;
  111.                 goto conv;
  112.                         
  113.                 /*  '?' base modifier  */
  114.                 
  115.             case '?':
  116.                 F.fetchBase = TRUE;
  117.                 c = *++fmt;
  118.                 goto conv;
  119.         
  120.                 /*  decimal (signed)  */
  121.                 
  122.             case 'd':
  123.                 base = 10;
  124.                 goto conv_signed;
  125.                 
  126.                 /*  integer (signed)  */
  127.                 
  128.             case 'i':
  129.                 base = 0;
  130.                 goto conv_signed;
  131.                 
  132.                 /*  octal (unsigned)  */
  133.             
  134.             case 'o':
  135.                 base = 8;
  136.                 goto conv_unsigned;
  137.                 
  138.                 /*  decimal (unsigned)  */
  139.             
  140.             case 'u':
  141.                 base = 10;
  142.                 goto conv_unsigned;
  143.                 
  144.                 /*  hexadecimal (unsigned)  */
  145.             
  146.             case 'p':
  147.                 F.lSize = TRUE;
  148.                 /* ... */
  149.             case 'x':
  150.             case 'X':
  151.                 base = 16;
  152.                 goto conv_unsigned;
  153.  
  154. #ifndef _NOFLOATING_
  155.                 /*  floating point  */
  156.  
  157.             case 'e':
  158.             case 'E':
  159.             case 'f':
  160.             case 'g':
  161.             case 'G':
  162.                 F.floating = TRUE;
  163.                 state = -1;
  164.                 goto scan;
  165. #endif _NOFLOATING_
  166.  
  167.                 /*  string  */
  168.             
  169.             case 's':
  170.                 do {
  171.                     c = getc(fp), ++nread;
  172.                 } while (isspace(c));
  173.                 clearset(1);
  174.                 goto string;
  175.                 
  176.                 /*  scanset  */
  177.             
  178.             case '[':
  179.                 c = *++fmt;
  180.                 if (c == '^') {
  181.                     F.negate = TRUE;
  182.                     c = *++fmt;
  183.                 }
  184.                 clearset(0);
  185.                 for (;;) {
  186.                     if (c == '\0')
  187.                         goto done;
  188.                     setbit((unsigned char) c);
  189.                     c = *++fmt;
  190.                     if (c == ']')
  191.                         break;
  192.                     if (c == '-' && fmt[1] != ']' && fmt[1] >= (first = fmt[-1])) {
  193.                         for (c = *++fmt; first != c; setbit(first++))
  194.                             ;
  195.                     }
  196.                 }
  197.                 if (F.negate)
  198.                     invertset();
  199.                 c = getc(fp), ++nread;
  200.                 goto string;
  201.                 
  202.                 /*  character  */
  203.             
  204.             case 'c':
  205.                 if (!F.haveWidth)
  206.                     F.fieldWidth = 1;
  207.                 if (!F.suppress)
  208.                     s = va_arg(arg, char *);
  209.                 while (F.fieldWidth-- > 0) {
  210.                     if ((c = getc(fp)) == EOF)
  211.                         goto done;
  212.                     if (!F.suppress)
  213.                         *s++ = c;
  214.                     ++nread;
  215.                 }
  216.                 if (!F.suppress)
  217.                     ++nassigned;
  218.                 ++nconverted;
  219.                 continue;
  220.  
  221.                 /*  store # bytes read so far  */
  222.                 
  223.             case 'n':
  224.                 result = nread;
  225.                 if (!F.suppress)
  226.                     --nassigned;
  227.                 goto assign;
  228.                 
  229.                 /*  others  */
  230.             
  231.             default:
  232.                 if (c != '%')
  233.                     goto done;
  234.             match1:
  235.                 if (isspace(c)) {
  236.                     do {
  237.                         c = getc(fp), ++nread;
  238.                     } while (isspace(c));
  239.                     ungetc(c, fp), --nread;
  240.                 }
  241.                 else {
  242.                     if ((c = getc(fp)) != (unsigned char) *fmt) {
  243.                         ungetc(c, fp);
  244.                         goto done;
  245.                     }
  246.                     ++nread;
  247.                 }
  248.                 continue;
  249.         }
  250.         /*NOTREACHED*/
  251.  
  252.             /*  string scanner  */
  253.             
  254. string:
  255.         if (!F.haveWidth)
  256.             F.fieldWidth = INT_MAX;
  257.         if (!F.suppress)
  258.             s = va_arg(arg, char *);
  259.         for (; c != EOF; c = getc(fp), ++nread) {
  260.             --F.fieldWidth;
  261.             if (!testbit(c))
  262.                 break;
  263.             F.valid = TRUE;
  264.             if (!F.suppress)
  265.                 *s++ = c;
  266.             if (F.fieldWidth == 0)
  267.                 goto endstring;
  268.         }
  269.         ungetc(c, fp), --nread;
  270. endstring:
  271.         if (!F.valid)
  272.             goto done;
  273.         if (!F.suppress) {
  274.             *s = 0;
  275.             ++nassigned;
  276.         }
  277.         ++nconverted;
  278.         continue;
  279.         
  280.             /*  integer conversions  */
  281.     
  282. conv_unsigned:
  283.         F.unsigned_ = TRUE;
  284. conv_signed:
  285.         if (F.fetchBase)
  286.             base = va_arg(arg, int);
  287.         state = 0;
  288.         
  289.             /*  numeric scanner  */
  290.         
  291. scan:    result = 0;
  292.         do {
  293.             c = getc(fp), ++nread;
  294.         } while (isspace(c));
  295.         if (!F.haveWidth)
  296.             F.fieldWidth = INT_MAX;
  297.         overflow = FALSE;
  298.         for (; c != EOF; c = getc(fp), ++nread) {
  299.             --F.fieldWidth;
  300.             switch (state) {
  301.                      
  302.                 /*  (integer) start state  */
  303.                      
  304.                 case 0:
  305.                     state = 1;
  306.                     if (c == '-') {
  307.                         F.negate = TRUE;
  308.                         break;
  309.                     }
  310.                     if (c == '+')
  311.                         break;
  312.                     /* ... */
  313.                     
  314.                 /*  (integer) look for leading '0'  */
  315.                         
  316.                 case 1:
  317.                     state = 3;
  318.                     if (c == '0') {
  319.                         F.valid = TRUE;
  320.                         if (F.fieldWidth) {
  321.                             if (base == 0) {
  322.                                 base = 8;
  323.                                 state = 2;
  324.                             }
  325.                             else if (base == 16)
  326.                                 state = 2;
  327.                         }
  328.                         break;
  329.                     }
  330.                     goto state3;
  331.                     
  332.                 /*  (integer) look for leading '0x'  */
  333.                 
  334.                 case 2:
  335.                     state = 3;
  336.                     if (c == 'x' || c == 'X') {
  337.                         base = 16;
  338.                         F.valid = FALSE;
  339.                         break;
  340.                     }
  341.                     /* ... */
  342.                 
  343.                 /*  (integer) process each digit  */
  344.                 
  345.                 case 3:
  346.                 state3:
  347.                     digit = c;
  348.                     if (digit >= '0' && digit <= '9')
  349.                         digit -= '0';
  350.                     else if (digit >= 'A' && digit <= 'Z')
  351.                         digit -= 'A' - 10;
  352.                     else if (digit >= 'a' && digit <= 'z')
  353.                         digit -= 'a' - 10;
  354.                     else
  355.                         goto pushback;
  356.                     if (base == 0)
  357.                         base = 10;
  358.                     if (digit >= base)
  359.                         goto pushback;
  360.                     asm {
  361.                         move.l    result,d0
  362.                         swap    d0
  363.                         mulu    base,d0
  364.                         swap    d0
  365.                         tst.w    d0
  366.                         bne.s    @1
  367.                         move.w    digit,d0
  368.                         mulu    base,result
  369.                         add.l    d0,result
  370.                         bcc.s    @2
  371.                 @1        st        overflow
  372.                 @2    }
  373.                     F.valid = TRUE;
  374.                     break;
  375.  
  376. #ifndef _NOFLOATING_
  377.                 /*  (floating) start state  */
  378.                 
  379.                 case -1:
  380.                     state = -2;
  381.                     D.exp = 0;
  382.                     D.sig[0] = 0;
  383.                     if (c == '-') {
  384.                         D.sgn = 1;
  385.                         break;
  386.                     }
  387.                     D.sgn = 0;
  388.                     if (c == '+')
  389.                         break;
  390.                     /* ... */
  391.                 
  392.                 /*  (floating) process each digit  */
  393.                 
  394.                 case -2:
  395.                     if (c >= '0' && c <= '9') {
  396.                         F.valid = TRUE;
  397.                         if (c != '0' || D.sig[0]) {
  398.                             if (D.sig[0] >= sizeof D.sig - 1) {
  399.                                 if (!F.dot)
  400.                                     ++D.exp;
  401.                                 break;
  402.                             }
  403.                             D.sig[++D.sig[0]] = c;
  404.                         }
  405.                         if (F.dot)
  406.                             --D.exp;
  407.                     }
  408.                     else if (c == '.' && !F.dot)
  409.                         F.dot = TRUE;
  410.                     else if ((c == 'e' || c == 'E') && F.valid) {
  411.                         base = 10;
  412.                         F.valid = FALSE;
  413.                         state = 0;
  414.                     }
  415.                     else
  416.                         goto pushback;
  417.                     break;
  418. #endif _NOFLOATING_
  419.             }
  420.             
  421.                 /*  get next character  */
  422.             
  423.             if (F.fieldWidth == 0)
  424.                 goto endscan;
  425.         }
  426.         
  427.             /*  push back last character read  */
  428.  
  429. pushback:    
  430.         ungetc(c, fp), --nread;
  431. endscan:
  432.         if (!F.valid)
  433.             goto done;
  434.             
  435.             /*  set sign of result  */
  436.             
  437.         if (F.negate && result) {
  438.             result = -result;
  439.             if (F.unsigned_ || result > 0)
  440.                 overflow = TRUE;
  441.         }
  442.         else if (!F.unsigned_ && result < 0)
  443.             overflow = TRUE;
  444.             
  445.             /*  see if result fits  */
  446.  
  447. #ifndef _NOFLOATING_
  448.         if (F.floating) asm {
  449.             movea.w    D.exp,a0
  450.             add.l    a0,result
  451.             bvs.s    @3
  452.             movea.l    result,a0
  453.             cmpa.w    a0,a0
  454.             beq.s    @4
  455.     @3        st        overflow
  456.     @4    }
  457.         else
  458. #endif _NOFLOATING_
  459.         if (F.hSize) {
  460.             if (F.unsigned_) {
  461.                 if ((unsigned short) result != result)
  462.                     overflow = TRUE;
  463.             }
  464.             else {
  465.                 if ((short) result != result)
  466.                     overflow = TRUE;
  467.             }
  468.         }
  469.         else if (!F.lSize) {
  470.             if (F.unsigned_) {
  471.                 if ((unsigned int) result != result)
  472.                     overflow = TRUE;
  473.             }
  474.             else {
  475.                 if ((int) result != result)
  476.                     overflow = TRUE;
  477.             }
  478.         }
  479.         
  480.             /*  report overflow  */
  481.             
  482.         if (overflow) {
  483.             if (F.unsigned_)
  484.                 result = 0;
  485.             else if (F.hSize || F.floating)
  486.                 result = SHRT_MIN;
  487.             else if (F.lSize)
  488.                 result = LONG_MIN;
  489.             else
  490.                 result = INT_MIN;
  491.             if (!F.negate)
  492.                 result = ~result;
  493.             if (!F.floating)
  494.                 errno = ERANGE;
  495.         }
  496.         
  497.             /*  assign result  */
  498.     
  499. assign:
  500.         if (!F.suppress) {
  501.             s = va_arg(arg, void *);
  502. #ifndef _NOFLOATING_
  503.             if (F.floating) {
  504.                 D.exp = result;
  505.                 if (F.lSize) {
  506. #if __option(double_8)
  507.                     F.hSize = TRUE;
  508. #else
  509.                     F.LSize = TRUE;
  510. #endif
  511.                 }
  512.                 if (F.LSize)
  513.                     dtof(FFEXT, &D, s);
  514.                 else if (F.hSize)
  515.                     dtof(FFDBL, &D, s);
  516.                 else
  517.                     dtof(FFSGL, &D, s);
  518.             }
  519.             else
  520. #endif _NOFLOATING_
  521.             if (F.lSize)
  522.                 * (long *) s = result;
  523.             else if (F.hSize)
  524.                 * (short *) s = result;
  525.             else
  526.                 * (int *) s = result;
  527.             ++nassigned;
  528.         }
  529.         ++nconverted;
  530.     }
  531.  
  532.         /*  all done!  */
  533.         
  534. done:
  535.     if (nconverted == 0 && c == EOF)
  536.         return(EOF);
  537.     return(nassigned);
  538. }
  539.  
  540.  
  541. /* ---------- scanset primitives ---------- */
  542.  
  543.  
  544. /*
  545.  *  clearset - initialize set to "nothing" or "everything but whitespace"
  546.  *
  547.  */
  548.  
  549. static void
  550. clearset(int whitespace)
  551. {
  552.     asm {
  553.         lea        scanset,a0
  554.         moveq    #0,d0
  555.         move.l    d0,(a0)+
  556.         move.l    d0,(a0)+
  557.         move.l    d0,(a0)+
  558.         move.l    d0,(a0)+
  559.         move.l    d0,(a0)+
  560.         move.l    d0,(a0)+
  561.         move.l    d0,(a0)+
  562.         move.l    d0,(a0)+
  563.     }
  564.     if (whitespace) {
  565.         scanset[1] = 0x3E;    /*  \t \n \v \f \r  */
  566.         scanset[4] = 0x01;    /*  space  */
  567.         invertset();
  568.     }
  569. }
  570.  
  571.  
  572. /*
  573.  *  setbit - add character to scan set
  574.  *
  575.  */
  576.  
  577. static void
  578. setbit(int c)
  579. {
  580.     scanset[c >> 3] |= (1 << (c & 7));
  581. }
  582.  
  583.  
  584. /*
  585.  *  invertset - complement scan set
  586.  *
  587.  */
  588.  
  589. static void
  590. invertset(void)
  591. {
  592.     asm {
  593.         lea        scanset,a0
  594.         not.l    (a0)+
  595.         not.l    (a0)+
  596.         not.l    (a0)+
  597.         not.l    (a0)+
  598.         not.l    (a0)+
  599.         not.l    (a0)+
  600.         not.l    (a0)+
  601.         not.l    (a0)+
  602.     }
  603. }
  604.  
  605.  
  606. /*
  607.  *  testbit - see if character is in scanset
  608.  *
  609.  */
  610.  
  611. static int
  612. testbit(int c)
  613. {
  614.     return(scanset[c >> 3] & (1 << (c & 7)));
  615. }
  616.  
  617.  
  618. /* ---------- floating-point conversion ---------- */
  619.  
  620.  
  621. #ifndef _NOFLOATING_
  622. static void
  623. dtof(short code, struct decrec *d, void *p)
  624. {
  625.     short excp, kind, c = '0';
  626. #if __option(mc68881) || !__option(native_fp)
  627.     register short *q = p;
  628.     
  629.     if (code == FFEXT)
  630.         p = q + 1;
  631. #endif
  632.     fp68k(&excp, (short) FPROCENTRY);
  633.     if (d->sig[0]) {
  634.         fp68k(d, p, (short) (FOD2B + code));
  635.         fp68k(&excp, (short) FGETENV);
  636.         fp68k(p, &kind, (short) (FOCLASS + code));
  637.         if (kind < 0)
  638.             kind = -kind;
  639.         if (kind == FCINF || (excp & (OVERFLOW<<8)))
  640.             c = 'I';
  641.         else if (kind == FCNORM && !(excp & (UNDERFLOW<<8)))
  642.             goto done;
  643.         errno = ERANGE;
  644.     }
  645.  
  646.         /*  result is zero or infinity  */
  647.  
  648.     if (c == '0')
  649.         d->sgn = 0;
  650.     d->exp = 0;
  651.     d->sig[0] = 1;
  652.     d->sig[1] = c;
  653.     fp68k(d, p, (short) (FOD2B + code));
  654.  
  655.         /*  done  */
  656.  
  657. done:
  658. #if __option(mc68881) || !__option(native_fp)
  659.     if (code == FFEXT) {
  660.         q[0] = q[1];
  661. #if __option(native_fp)
  662.         q[1] = 0;
  663. #endif
  664.     }
  665. #endif
  666.     return;
  667. }
  668. #endif _NOFLOATING_
  669.